using System;
using System.Collections.Generic;

namespace Rage.Base.Abilities
{
    /* http://www.swtor.com/community/showthread.php?t=425
     * Modified Armor Value (MAV)
     * * SI: (BAV Light 1909)*(Stance 2.5) or 1909*2.5 = 4772.5*(Eye of the Storm 20%) or 1.2*4772.5 = 5727
     * * SW: (BAV Heavy 3601)*(Stance 1.6) or 3601*1.6 = 5761.6
     * * BH: (BAV Heavy 3601)*(Stance 1.6) or 3601*1.6 = 5761.6*(Rebraced Armor +16%) or 5761.6*1.16 = 6683.5
     * * * Note: Armor bonuses are multiplicative exceptions to TOR's mountains of additive calcs.  Now, we plug our MAV into our DR calculation
     *     (found in the Game Calculations section) to come up with our Base Armor DR (BADR):
     * * Base Armor DR (BADR): SI = 34.65% | SW = 34.78% | BH = 38.22%

     * Modified Base Armor DR 
     * TOR handles passive skill bonuses additively and NOT multiplicatively so let's plug in current DR passive skills:
     * * SI: (BADR 34.65%) + (Sith Defiance 2%) = 36.65% 
     * * SW: (BADR 34.78%) + (Stance 6%) = 40.78%
     * * BH: (BADR 38.22%) + (Stance 5%) + (Ion Shield 2%) + (Power Armor 2%) = 47.22%

     * Resistance: Elemental/Internal DR
     * As mentioned earlier in this thread, Elemental/Internal DR does NOT factor in Armor.  So after subtracting Armor and adding passive
     * Elemental/Internal bonuses we get the following:
     * * SI: (Sith Defiance 2%) + (Charge Mastery 9%) = 11%
     * * SW: (Stance 6%) + (Dark Blood 4%) = 10%
     * * BH: (Stance 5%) + (Ion Shield 2%) + (Power Armor 2%) = 9%

     * Situational Modifiers
     * These are situational modifiers from abilities that directly affect DR.  I mention these separately because the effects are longer than the
     * CD so they can be applied constantly but are situational as not ALL targets on the board will be under their influence at ALL times.
     * * SI: (Wither 5%)
     * * SW: (Sonic Barrier Value Unknown)
     * * BH: (Combust 4%)

     * Shield Chance
     * For the purposes of simplicity we are going to assume a ShieldRating of 0
     * * SI: (Shield Base 5%) + (Stance 15%) + (Dark Ward 15%) = 35%
     * * SW: (Shield Base 5%) + (Stance 15%) + (Shield Specialization 4%)  = 24%
     * * BH: (Premium Shield Base 5%) + (Stance 15%) + (Shield Vents 2% + Empowered Tech 10%) = 32%

     * Shield Absorption
     * For purposes of simplicity we are going to assume a AbsorptionRating of 0
     * * SI: (Premium Shield Base 20%) + (Hollow 4%) = 24%
     * * SW: (Premium Shield Base 20%) = 20%
     * * BH: (Premium Shield Base 20%) + (Ablative Upgrades 6%) = 26%

     * Avoidance: Ranged Deflection & Melee Parry
     * For purposes of simplicity we are going to assume a DFR of 0
     * * SI: (Base 10%) + (Premonition 2%) + (Lightning Reflexes 4%) = 16% or 21% w/Discharge
     * * SW: (Base 5%) + (Guard Stance 6%) + (Blade Barricade 6%) = 17% or 22% w/Smash
     * * BH: (Base 5%) = 5%

     * Mean Mitigation
     * A=Avoidance
     * B=Shield Chance
     * C=Shield Absorption
     * D=MBADR

     * 1f-(1f-A)(1f-D)(B*(1f-C)+(1f-B)) = Mean Mitigation

     * Make sure to put your percentages into decimal format.
     * Example:
     * Sith Inquisitor Assassin
     * A= 0.16f
     * B= 0.35f
     * C= 0.24f
     * D= 0.3665f
     * Results in: 1f-(1f-0.16f)(1f-0.3665f)(0.35f*(1f-0.24f)+(1f-0.35f)) = 51.26% Mean Mitigation
     * 
     * Mean Mitigation w/ Crit% Factor
     * A= Avoidance
     * B= Shield Chance
     * C= Shield Absorption
     * D= MBADR
     * X= Mob's crit chance (so if mob has a 48% chance of critting then X= 0.48)
     * Y= Mob's crit multiplier (to our knowledge this is a static 1.5% modififer)
     * 1f-(1f-A)(1f-D)(B*(1f-C)+1f-B+X*(Y-1f)) = Mean Mitigation
     * Example:Sith Inquisitor Assassin

     * A= 0.16f
     * B= 0.35f
     * C= 0.24f
     * D= 0.3665f
     * X= 0.25f
     * Y= 1.5f
     * Results in: 1f-(1f-0.16f)(1f-0.3665f)(0.35f*(1f-0.24f)+1f-0.35f+0.25f*(1.5f-1f)) = 0.4460f or 44.6% Mean Mitigation
     */
    public class CombatFactors
    {
        public CombatFactors() { }
        public CombatFactors(Character character, Stats stats, ICalculationOptionBase calcOpts, BossOptions bossOpts)
        {
            Char = character;
            MH = Char == null || Char.MainHand == null ? new Knuckles() : Char.MainHand.Item;
            OH = Char == null || Char.OffHand == null || (Char.MarauderTalents.Annihilate == 0 && Char.MarauderTalents.Annihilate == 0) ? null : Char.OffHand.Item;
            Talents = Char == null || Char.MarauderTalents == null ? new MarauderTalents() : Char.MarauderTalents;
            CalcOpts = calcOpts; // (calcOpts == null ? new ICalculationOptionBase() : calcOpts);
            BossOpts = (bossOpts == null ? new BossOptions() : bossOpts);
            StatS = stats;
            CritProcs = new WeightedStat[] { new WeightedStat() { Chance = 1f, Value = 0f } };
            InvalidateCache();
        }

        private WeightedStat[] _critProcs;
        public WeightedStat[] CritProcs { get { return _critProcs; } set { _critProcs = value; } }
        private void SetCvalues()
        {
            if (MH != null) { C_MHItemType = MH.Type; }
            if (OH != null) { C_OHItemType = OH.Type; }
            useMH = _useMH;
            useOH = _useOH;

            // Player Defensive Stats
            C_PlayersDefense = PlayersDefense;
            C_TargetsChanceToMissThePlayer = TargetsChanceToMissThePlayer;
            C_PlayersChanceToDodgeTargetAttacks = PlayersChanceToDodgeTargetAttacks;
            C_PlayersChanceToParryTargetAttacks = PlayersChanceToParryTargetAttacks;
            C_PlayersChanceToShieldTargetAttacks = PlayersChanceToShieldTargetAttacks;
            C_TargetsChanceToCritThePlayer = TargetsChanceToCritThePlayer;

            // Player's Offensive Stats (Target's Defensive)
            C_PlayersChanceToBeShielded = PlayersChanceToBeShielded;

            C_AccuracyPercMh_Basic = AccuracyPercMh_Basic;
            C_AccuracyPercMh_Force = AccuracyPercMh_Force;
            C_PlayersChanceToMissMh_Basic = PlayersChanceToMissMh_Basic;
            C_PlayersChanceToMissMh_Force = PlayersChanceToMissMh_Force;
            C_PlayersMhChanceToBeDodged_Basic = PlayersMhChanceToBeDodged_Basic;
            C_PlayersMhChanceToBeDodged_Force = PlayersMhChanceToBeDodged_Force;
            C_PlayersMhChanceToBeParried_Basic = PlayersMhChanceToBeParried_Basic;
            C_PlayersMhChanceToBeParried_Force = PlayersMhChanceToBeParried_Force;
            C_PlayersMhChanceToCritTarget_Basic = PlayersMhChanceToCritTarget_Basic;
            C_PlayersMhChanceToCritTarget_Force = PlayersMhChanceToCritTarget_Force;
            if (useOH)
            {
                C_AccuracyPercOh_Basic = AccuracyPercOh_Basic;
                C_AccuracyPercOh_Force = AccuracyPercOh_Force;
                C_PlayersChanceToMissOh_Basic = PlayersChanceToMissOh_Basic;
                C_PlayersChanceToMissOh_Force = PlayersChanceToMissOh_Force;
                C_PlayersOhChanceToBeDodged_Basic = PlayersOhChanceToBeDodged_Basic;
                C_PlayersOhChanceToBeDodged_Force = PlayersOhChanceToBeDodged_Force;
                C_PlayersOhChanceToBeParried_Basic = PlayersOhChanceToBeParried_Basic;
                C_PlayersOhChanceToBeParried_Force = PlayersOhChanceToBeParried_Force;
                C_PlayersOhChanceToCritTarget_Basic = PlayersOhChanceToCritTarget_Basic;
                C_PlayersOhChanceToCritTarget_Force = PlayersOhChanceToCritTarget_Force;
            } else {
                C_OHItemType = ItemType.None;
                C_AccuracyPercOh_Basic = 0f;
                C_AccuracyPercOh_Force = 0f;
                C_PlayersChanceToMissOh_Basic = 0f;
                C_PlayersChanceToMissOh_Force = 0f;
                C_PlayersOhChanceToBeDodged_Basic = 0f;
                C_PlayersOhChanceToBeDodged_Force = 0f;
                C_PlayersOhChanceToBeParried_Basic = 0f;
                C_PlayersOhChanceToBeParried_Force = 0f;
                C_PlayersOhChanceToCritTarget_Basic = 0f;
                C_PlayersOhChanceToCritTarget_Force = 0f;
            }
        }
        #region Global Variables
        public Stats StatS { get { return _stats; } set { _stats = value; } }
        protected Stats _stats;
        public TalentsBase Talents { get { return _talents; } set { _talents = value; } }
        private TalentsBase _talents;
        public ICalculationOptionBase CalcOpts { get { return _calcOpts; } set { _calcOpts = value; } }
        private ICalculationOptionBase _calcOpts { get; set; }
        public BossOptions BossOpts { get; protected set; }
        public Character Char { get; protected set; }
        public Item MH { get; protected set; }
        public Item OH { get; protected set; }

        // The following variables store information so that it is not recalculated
        // multiple times in the same Character.GetCalc, saves a lot of performance
        public ItemType C_MHItemType { get; private set; }
        public ItemType C_OHItemType { get; private set; }

        public float C_AccuracyPercMh_Basic { get; private set; }
        public float C_AccuracyPercMh_Force { get; private set; }
        public float C_AccuracyPercOh_Basic { get; private set; }
        public float C_AccuracyPercOh_Force { get; private set; }

        public float C_PlayersChanceToMissMh_Basic { get; private set; }
        public float C_PlayersChanceToMissMh_Force { get; private set; }
        public float C_PlayersChanceToMissOh_Basic { get; private set; }
        public float C_PlayersChanceToMissOh_Force { get; private set; }
        public float C_TargetsChanceToMissThePlayer { get; private set; }

        public float C_PlayersDefense { get; private set; }

        public float C_PlayersMhChanceToBeDodged_Basic { get; private set; }
        public float C_PlayersOhChanceToBeDodged_Basic { get; private set; }
        public float C_PlayersMhChanceToBeDodged_Force { get; private set; }
        public float C_PlayersOhChanceToBeDodged_Force { get; private set; }
        public float C_PlayersChanceToDodgeTargetAttacks { get; private set; }

        public float C_PlayersMhChanceToBeParried_Basic { get; private set; }
        public float C_PlayersOhChanceToBeParried_Basic { get; private set; }
        public float C_PlayersMhChanceToBeParried_Force { get; private set; }
        public float C_PlayersOhChanceToBeParried_Force { get; private set; }
        public float C_PlayersChanceToParryTargetAttacks { get; private set; }

        public float C_PlayersChanceToShieldTargetAttacks { get; private set; }
        public float C_PlayersChanceToBeShielded { get; private set; }

        public float C_PlayersMhChanceToCritTarget_Basic { get; private set; }
        public float C_PlayersOhChanceToCritTarget_Basic { get; private set; }
        public float C_PlayersMhChanceToCritTarget_Force { get; private set; }
        public float C_PlayersOhChanceToCritTarget_Force { get; private set; }
        public float C_TargetsChanceToCritThePlayer { get; private set; }

        public int LevelDif { get { return BossOpts.Level - Char.Level; } }
        #endregion

        public bool useMH; private bool _useMH { get { return MH != null; } }
        public bool useOH; private bool _useOH { get { return OH != null && OH.Type != ItemType.Shield && OH.Type != ItemType.Focus && OH.Type != ItemType.Generator; } }

        public virtual void InvalidateCache() {
            _PlayersDamageBonus
          = _PlayersDamageBonusMultiplier
          = _TargetsDamageReductionMultiplier
          = _critDamageMultiplier
            = -1f;
            _AttackTableBasicMH = _AttackTableBasicOH = null;
            SetCvalues();
        }

        private float GetValueOfMainStatForClass(CharacterClass charClass)
        {
            switch (charClass)
            {
                case CharacterClass.Juggernaut:
                case CharacterClass.Marauder:
                case CharacterClass.Guardian:
                case CharacterClass.Sentinel:
                    { return StatS.Strength; }
                case CharacterClass.Powertech:
                case CharacterClass.Mercenary:
                case CharacterClass.Vanguard:
                case CharacterClass.Commando:
                    { return StatS.Aim; }
                case CharacterClass.Assassin:
                case CharacterClass.Sorcerer:
                case CharacterClass.Sage:
                case CharacterClass.Shadow:
                    { return StatS.Cunning; }
                case CharacterClass.Operative:
                case CharacterClass.Sniper:
                case CharacterClass.Gunslinger:
                case CharacterClass.Scoundrel:
                    { return StatS.Willpower; }
                default: { return 0f; }
            }
        }

        #region Weapon Damage Calcs
        #region Major Damage Factors
        private float _PlayersDamageBonusMultiplier = -1f, _TargetsDamageReductionMultiplier = -1f, _PlayersHealingReceivedBonusMultiplier = -1f;
        private float _PlayersDamageBonus = -1f;
        /// <summary>A Percentage Value. 1.00 = No Modifier. 1.25 = +25% Modifier</summary>
        public virtual float PlayersDamageBonus
        {
            get
            {
                // General Bonuses
                if (_PlayersDamageBonus == -1f)
                {
                    _PlayersDamageBonus  = 0f;
                    _PlayersDamageBonus += StatS.Strength * 0.2f;
                    _PlayersDamageBonus += StatS.ForcePower * 0.23f;
                    _PlayersDamageBonus += StatS.Power * 0.23f;
                }
                return _PlayersDamageBonus;
            }
        }
        public virtual float PlayersDamageBonusMultiplier
        {
            get {
                // General Bonuses
                if (_PlayersDamageBonusMultiplier == -1f) {
                    _PlayersDamageBonusMultiplier = (1f + StatS.BonusDamageMultiplier)
                                 * (1f + StatS.BonusKineticDamageMultiplier);
                }
                return _PlayersDamageBonusMultiplier;
            }
        }
        public virtual float TargetsDamageReductionMultiplier {
            get {
                if (_TargetsDamageReductionMultiplier == -1f) {
                    float arpenBuffs = StatS.ArmorPenetration;

                    _TargetsDamageReductionMultiplier = 1f - StatConversion.GetArmorDamageReduction(
                        BossOpts.Armor,
                        StatS.TargetArmorReduction, arpenBuffs);
                }
                return _TargetsDamageReductionMultiplier;
            }
        }
        public virtual float PlayersHealingReceivedBonusMultiplier {
            get {
                // General Bonuses
                if (_PlayersHealingReceivedBonusMultiplier == -1f)
                {
                    _PlayersHealingReceivedBonusMultiplier = (1f + StatS.BonusHealingReceived);
                }
                return _PlayersHealingReceivedBonusMultiplier;
            }
        }
        #endregion
        #region Weapon Damage
        // TODO: Recreate the Core Weapon Damage Values for Combat Factors
        #endregion
        #region Weapon Crit Damage
        private float _critDamageMultiplier = -1f;
        public float CritDamageMultiplier
        {
            get {
                if (_critDamageMultiplier == -1f) {
                    _critDamageMultiplier = 0.50f + StatConversion.GetCritDamageMultiplierFromSurgeRating(StatS.SurgeRating * (1f + StatS.BonusSurgeRatingMultiplier));
                }
                return _critDamageMultiplier;
            }
        }
        #endregion
        #region Weapon Blocked Damage
        public float TargetsShieldedDamageReductionMultiplier { get { return 1f - 0f; } }
        public float PlayersShieldedDamageReductionMultiplier { get { return 1f - StatS.Absorb; } }
        #endregion
        #region Speed
        // TODO Redo this section (Alacrity Speed Bonuses for Cast times and Channels
        #endregion
        #endregion
        #region Attack Table
        private AttackTable _AttackTableBasicMH, _AttackTableBasicOH;
        public AttackTable AttackTableBasicMH
        {
            get
            {
                if (_AttackTableBasicMH == null)
                {
                    _AttackTableBasicMH = new AttackTable(Char, StatS, this, BossOpts, ClassAbility.NULL, true, false);
                }
                return _AttackTableBasicMH;
            }
        }
        public AttackTable AttackTableBasicOH
        {
            get
            {
                if (_AttackTableBasicOH == null)
                {
                    _AttackTableBasicOH = new AttackTable(Char, StatS, this, BossOpts, ClassAbility.NULL, false, false);
                }
                return _AttackTableBasicOH;
            }
        }
        #region Accuracy Rating To Perc
        public float AccuracyPercMh_Basic { get { return StatConversion.GetBasicMhAccuracyFromRating(StatS.AccuracyRating) + PlayersMissChancePercBonuses; } }
        public float AccuracyPercMh_Force { get { return StatConversion.GetForceMhAccuracyFromRating(StatS.AccuracyRating) + PlayersMissChancePercBonuses + StatS.BonusForceAccuracy; } }
        public float AccuracyPercOh_Basic { get { return StatConversion.GetBasicOhAccuracyFromRating(StatS.AccuracyRating) + PlayersMissChancePercBonuses; } }
        public float AccuracyPercOh_Force { get { return StatConversion.GetForceOhAccuracyFromRating(StatS.AccuracyRating) + PlayersMissChancePercBonuses + StatS.BonusForceAccuracy; } }
        #endregion
        #region Miss
        // NOTE: Accuracy beyond 100% reduces target Defense
        private float PlayersMissChancePercBonuses { get { return StatS.BonusAccuracy; } }
        private float PlayersChanceToMissMh_Basic { get { return Math.Max(0f, StatConversion.BASIC_MISS_CHANCE_CAP[LevelDif] - (AccuracyPercMh_Basic - 0.90f)); } }
        private float PlayersChanceToMissOh_Basic { get { return Math.Max(0f, StatConversion.BASIC_MISS_CHANCE_CAP[LevelDif] - (AccuracyPercOh_Basic - 0.90f)); } }
        private float PlayersChanceToMissMh_Force { get { return Math.Max(0f, StatConversion.FORCE_MISS_CHANCE_CAP[LevelDif] - (AccuracyPercMh_Force - 0.90f)); } }
        private float PlayersChanceToMissOh_Force { get { return Math.Max(0f, StatConversion.FORCE_MISS_CHANCE_CAP[LevelDif] - (AccuracyPercOh_Force - 0.90f)); } }
        // TODO: See if Player Defense increases chance for Target to Miss
        private float TargetsChanceToMissThePlayer { get { return Math.Max(0f, StatConversion.BASIC_MISS_CHANCE_CAP[LevelDif]); } }
        #endregion
        #region Defense
        private float PlayersDefense { get { return StatS == null ? 0 : StatS.Defense; } }
        #endregion
        #region Dodge
        private float DodgeChanceCap { get { return StatConversion.BOTH_DODGE_CHANCE_CAP[LevelDif]; } } // Half of 8%
        private float PlayersMhChanceToBeDodged_Basic { get { return Math.Max(0f, DodgeChanceCap - Math.Abs(Math.Min(0f, StatConversion.BASIC_MISS_CHANCE_CAP[LevelDif] - (AccuracyPercMh_Basic - 0.90f))) / 2f); } }
        private float PlayersOhChanceToBeDodged_Basic { get { return Math.Max(0f, DodgeChanceCap - Math.Abs(Math.Min(0f, StatConversion.BASIC_MISS_CHANCE_CAP[LevelDif] - (AccuracyPercOh_Basic - 0.90f))) / 2f); } }
        private float PlayersMhChanceToBeDodged_Force { get { return Math.Max(0f, DodgeChanceCap - Math.Abs(Math.Min(0f, StatConversion.FORCE_MISS_CHANCE_CAP[LevelDif] - (AccuracyPercMh_Force - 0.90f))) / 2f); } }
        private float PlayersOhChanceToBeDodged_Force { get { return Math.Max(0f, DodgeChanceCap - Math.Abs(Math.Min(0f, StatConversion.FORCE_MISS_CHANCE_CAP[LevelDif] - (AccuracyPercOh_Force - 0.90f))) / 2f); } }
        private float PlayersChanceToDodgeTargetAttacks { get { return PlayersDefense / 2f; } }
        #endregion
        #region Parry
        private float ParryChanceCap { get { return StatConversion.Both_PARRY_CHANCE_CAP[LevelDif]; } } // Half of 8%
        private float PlayersMhChanceToBeParried_Basic { get { return Math.Max(0f, ParryChanceCap - Math.Abs(Math.Min(0f, StatConversion.BASIC_MISS_CHANCE_CAP[LevelDif] - (AccuracyPercMh_Basic - 0.90f))) / 2f); } }
        private float PlayersOhChanceToBeParried_Basic { get { return Math.Max(0f, ParryChanceCap - Math.Abs(Math.Min(0f, StatConversion.BASIC_MISS_CHANCE_CAP[LevelDif] - (AccuracyPercOh_Basic - 0.90f))) / 2f); } }
        private float PlayersMhChanceToBeParried_Force { get { return Math.Max(0f, ParryChanceCap - Math.Abs(Math.Min(0f, StatConversion.BASIC_MISS_CHANCE_CAP[LevelDif] - (AccuracyPercMh_Force - 0.90f))) / 2f); } }
        private float PlayersOhChanceToBeParried_Force { get { return Math.Max(0f, ParryChanceCap - Math.Abs(Math.Min(0f, StatConversion.BASIC_MISS_CHANCE_CAP[LevelDif] - (AccuracyPercOh_Force - 0.90f))) / 2f); } }
        private float PlayersChanceToParryTargetAttacks { get { return PlayersDefense / 2f; } }
        #endregion
        #region Shield
        private float PlayersChanceToBeShielded { get { return 0f; } } // TODO verify Bosses no have shields?
        private float PlayersChanceToShieldTargetAttacks { get { return Math.Max(0f, Math.Min(StatConversion.BOTH_SHIELD_CHANCE_CAP[LevelDif], StatS.Shield)); } }
        #endregion
        #region Crit
        private float PlayersMhChanceToCritTarget_Basic { get { return !useMH ? 0f : StatS.BonusCritChance + StatS.BonusBasicCritChance; } }
        private float PlayersOhChanceToCritTarget_Basic { get { return !useOH ? 0f : StatS.BonusCritChance + StatS.BonusBasicCritChance; } }
        private float PlayersMhChanceToCritTarget_Force { get { return !useMH ? 0f : StatS.BonusCritChance + StatS.BonusForceCritChance; } }
        private float PlayersOhChanceToCritTarget_Force { get { return !useOH ? 0f : StatS.BonusCritChance + StatS.BonusForceCritChance; } }
        private float TargetsChanceToCritThePlayer { get { return 0.05f; } }
        #endregion
        #endregion
        #region Other
        protected class Knuckles : Item
        {
            public Knuckles()
            {
                MaxDamage = 0;
                MinDamage = 0;
            }
        }
        #endregion


        public static float GlobalCooldownSpeed(CollectedCharacter collChar, bool withLatency = false, float latency = 0f) { return 1.5f + (withLatency ? latency : 0f); }

        public static float TargetsChanceToCritPlayer(CollectedCharacter collChar) { return Math.Max(0.0f, 0.05f - AvoidanceChance(collChar, HitResult.Crit)); }

        public static float PlayersInternalAndElementalReductionFromAnywhere(CollectedCharacter collChar, Rage.ItemDamageType school, int stance = 0)
        {
            float totalResist = 0.0f;
            switch (school)
            {
                case Rage.ItemDamageType.Internal: totalResist = collChar.StatS.InternalResistance; break;
                case Rage.ItemDamageType.Elemental: totalResist = collChar.StatS.ElementalResistance; break;
                default: return 0f;
            }

            float globalDamageTakenReductionMultiplier = PlayersDamageReductionFromStance(collChar, stance);
            float averageResistance = StatConversion.GetAverageResistance(collChar.BossOpts.Level, collChar.Char.Level, totalResist, 0.0f);

            return Math.Max(0.0f, globalDamageTakenReductionMultiplier * (1.0f - averageResistance));
        }

        public static float PlayersDamageBonusFromStance(CollectedCharacter collChar, int Stance)
        {
            switch ((JuggStances)Stance)
            {
                case JuggStances.ShienForm: { return 1f + 0.06f; }
                case JuggStances.ShiiChoForm: { return 1f + 0.03f; }
                case JuggStances.SoresuForm: { return 1f + 0.00f; }
                default: { return 1f + 0.00f; }
            }
        }
        public static float PlayersDamageReductionFromStance(CollectedCharacter collChar, int Stance)
        {
            switch ((JuggStances)Stance)
            {
                case JuggStances.ShienForm:   { return 1f - 0.00f; }
                case JuggStances.ShiiChoForm: { return 1f - 0.03f; }
                case JuggStances.SoresuForm:  { return 1f - 0.06f; }
                default:                      { return 1f - 0.00f; }
            }
        }
        /// <summary>
        /// This should be a positive number factoring your Defensive Stance (-10% damage taken)
        /// and your stats.DamageTakenReductionMultiplier
        /// </summary>
        /// <returns>A Percentage (1f - (1f - 0.10f) * (1f - player.Stats.DamageTakenReductionMultiplier))</returns>
        public static float PlayersDamageReductionFromStanceAndArmorOrTalents(CollectedCharacter collChar, Rage.ItemDamageType damageType, int stance)
        {
            // In Defensive Stance
            float globalDamageTakenReductionMultiplier = PlayersDamageReductionFromStance(collChar, stance);

            switch (damageType)
            {
                case Rage.ItemDamageType.Kinetic: return globalDamageTakenReductionMultiplier * (1f - StatConversion.GetArmorDamageReduction(collChar.StatS.Armor, 0f, 0f));
                case Rage.ItemDamageType.Energy: return globalDamageTakenReductionMultiplier * (1f - StatConversion.GetArmorDamageReduction(collChar.StatS.Armor, 0f, 0f));
                case Rage.ItemDamageType.Internal: return globalDamageTakenReductionMultiplier * PlayersInternalAndElementalReductionFromAnywhere(collChar, ItemDamageType.Internal);
                case Rage.ItemDamageType.Elemental: return globalDamageTakenReductionMultiplier * PlayersInternalAndElementalReductionFromAnywhere(collChar, ItemDamageType.Internal);
                default: return globalDamageTakenReductionMultiplier;
            }
        }

        public static float AvoidanceChance(CollectedCharacter collChar, HitResult avoidanceType)
        {
            switch (avoidanceType)
            {
                case HitResult.Crit:
                    return StatConversion.GetDRAvoidanceChance(collChar.Char, collChar.StatS, avoidanceType, collChar.BossOpts.Level) /*+ (collChar.Talents.Accuracy * 0.01f)*/;
                default:
                    return Math.Max(0.0f, StatConversion.GetDRAvoidanceChance(collChar.Char, collChar.StatS, avoidanceType, collChar.BossOpts.Level));
            }
        }

    }
}
